package com.zhidian.edm.config;

import com.alibaba.fastjson2.JSON;
import com.zhidian.edm.entity.SysTokenPO;
import com.zhidian.edm.result.ResultResponse;
import com.zhidian.edm.service.ISysTokenService;
import com.zhidian.edm.service.impl.UserDetailsServiceImpl;
import com.zhidian.edm.util.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private ISysTokenService iSysTokenService;


    @Resource
    private UserDetailsServiceImpl userDetailsService;

    // 完整的排除路径列表（覆盖Swagger所有资源和公开接口）
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
            "/login", "/logout",
            "/swagger-ui/index.html", "/swagger-ui.html", "/swagger-ui",
            "/v3/api-docs", "/v3/api-docs/**",
            "/api-docs",
            "/webjars", "/webjars/**",
            "/swagger-resources", "/swagger-resources/**"
    );


    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
        String requestUri = req.getRequestURI();
        // 1. 检查是否为排除路径（前缀匹配）
        boolean isExcluded = EXCLUDE_PATHS.stream()
                .anyMatch(requestUri::startsWith);
        if (isExcluded) {
            chain.doFilter(req, res);
            return;
        }
        String token = req.getHeader("Authorization");
        if (!StringUtils.hasText(token)) {
            sendErrorResponse(res, HttpStatus.UNAUTHORIZED.value(), "未提供有效的Token");
            return;
        }

        try {
            jwtUtil.parseToken(token);
            Optional<SysTokenPO> dbToken = iSysTokenService.findByToken(token);
            if (dbToken.isEmpty() || dbToken.get().getExpiredTime().isBefore(LocalDateTime.now())) {
                throw new RuntimeException("Invalid token");
            }

            if (dbToken.get().getExpiredTime().isBefore(LocalDateTime.now())) {
                throw new RuntimeException("Token expired");
            }

            Claims claims = jwtUtil.parseToken(token).getBody();
            Long userId = Long.valueOf(claims.getSubject());
            UserDetails userDetails = userDetailsService.loadUserById(userId);
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(auth);
        } catch (JwtException | IllegalArgumentException e) {
            // token invalid => clear context
            SecurityContextHolder.clearContext();
            sendErrorResponse(res, HttpStatus.UNAUTHORIZED.value(), "未提供有效的Token");
            return;
        }

        chain.doFilter(req, res);
    }

    private void sendErrorResponse(HttpServletResponse response, int code, String message) throws IOException {
        // 设置响应内容类型为JSON
        response.setContentType("application/json;charset=UTF-8");
        // 设置HTTP状态码
        response.setStatus(HttpStatus.OK.value());
        // 构建统一返回结果并通过FastJSON转为JSON字符串
        ResultResponse<Void> errorResult = ResultResponse.fail(code, message);
        response.getWriter().write(JSON.toJSONString(errorResult));
    }
}